package com.study.kt._01grammar._02oop

import java.util.*

fun main() {
    val p = Person()
    //可以直接访问属性，因为kotlin默认帮我们实现了get、set方法
    p.name = "slx" //调用setName方法
    println(p.name) //调用getName方法

    val animal = Animal("水水", 12)
    println(animal.age)

    val animal2 = Animal2("haha", 12, "123")
    val animal22 = Animal2("haha", 12, 12f)

    animal2.address = "qd"
    println(animal2.address)

    //类的构造函数 属性有默认值，可以直接使用默认构造参数
    val a4 = Animal()

    //使用类中延迟初始化的字段
    val customGetSet = CustomGetSet("sun", "slx")
    //birth字段为延迟初始化，此处没有初始化直接使用就会报错
    //println(customGetSet.birth)
    customGetSet.birth = Date()
    println(customGetSet.birth)
}

//定义了类同时指定主构造函数，如果类中没有其他内容，可以省略大括号
//可以在外界访问 属性
//可以为类的构造函数添加默认值
class Animal(var name: String = "fauks", var age: Int = 1)

//使用val声明了构造参数，可以访问字段，但是不能修改字段
//使用var 相当于java的 private String name;并实现了get、set方法
//使用val 相当于java的private final String name,仅实现了get方法
class Animal2(val name: String, val age: Int) {
    //定义次构造函数，例如phone字段，可以选填，但是主构造函数的值必须传
    //次构造函数必须调用主构造函数 this(name,age)

    //次构造函数不能使用var val使用，要想使用必须单独定义一个属性
    constructor(name: String, age: Int, phone: String) : this(name, age)

    var score = 10f

    //为了防止空指针，对象类型的属性声明后必须初始化
    //有时候我们无法初始化属性(例如Android中的View) 可以使用lateinit延迟初始化
    lateinit var desc: String

    var grade: Int = 0
        private set // 默认为public，显示指定为private

    //属性的getter、setter方法,一般不需要写
    var address: String = ""
        // get方法不能直接返回address，因为backing field的存在
        get() = field //field表示属性本身,给address赋值实质上是给field赋值，只能在get、set方法中使用
        set(value) {
            field = value
        }

    //通过this关键字，将name、age两个字段委托给主构造函数
    constructor(name: String, age: Int, score: Float) : this(name, age) {
        //此时外界就可以访问score字段，否则无法直接访问score
        //定义后保存字段
        this.score = score
    }

}

// 修改变量的可见性
class Person {
    var name: String = "fauks"

    //修改属性的可见性
    var age = 10
        // 私有化set方法,则无法调用setAge方法
        private set

    //set、get方法都无法访问
    private var desc = "青岛"
}

//自定义getter、setter方法
class CustomGetSet(firstName: String, secondName: String) {

    //在定义一个字段后，会为属性生成getter、setter、field(field关键字被称为幕后属性)
    //有幕后属性的字段必须赋初始值，要么在构造方法时，要么在定义属性时
    var firstName: String = firstName
    var secondName: String = secondName

    //延迟初始化
    lateinit var birth: Date

    //使用private修饰的字段为幕后属性，外界无法访问
    private var _name: String = name

    //如果外界需要访问，需要提供一个public的字段，设置、获取幕后字段
    var name: String
        get() = _name
        set(value) {
            _name = value
        }

    //定义一个不保存数据的字段
    var fullName: String
        get() = "$firstName+$secondName"
        set(value) {
            val split = value.split("-")
            firstName = split[0]
            secondName = split[1]
        }
}